package com.qianfeng.netty.http;

//
//                            _ooOoo_  
//                           o8888888o  
//                           88" . "88  
//                           (| -_- |)  
//                            O\ = /O  
//                        ____/`---'\____  
//                      .   ' \\| |// `.  
//                       / \\||| : |||// \  
//                     / _||||| -:- |||||- \  
//                       | | \\\ - /// | |  
//                     | \_| ''\---/'' | |  
//                      \ .-\__ `-` ___/-. /  
//                   ___`. .' /--.--\ `. . __  
//                ."" '< `.___\_<|>_/___.' >'"".  
//               | | : `- \`.;`\ _ /`;.`/ - ` : | |  
//                 \ \ `-. \_ __\ /__ _/ .-` / /  
//         ======`-.____`-.___\_____/___.-`____.-'======  
//                            `=---='  
//  
//         .............................................  
//                  佛祖镇楼                  BUG辟易  
//          佛曰:  
//                  写字楼里写字间，写字间里程序员；  
//                  程序人员写程序，又拿程序换酒钱。  
//                  酒醒只在网上坐，酒醉还来网下眠；  
//                  酒醉酒醒日复日，网上网下年复年。  
//                  但愿老死电脑间，不愿鞠躬老板前；  
//                  奔驰宝马贵者趣，公交自行程序员。  
//                  别人笑我忒疯癫，我笑自己命太贱；  
//  


import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Jackiechan on 2022/4/1 20:56
 *
 * @author Jackiechan
 * @version 1.0
 * @since 1.0
 */
public class MyHttpControllerHandler extends SimpleChannelInboundHandler<HttpObject> {
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception {
        //当我们收到http请求的时候就会执行这个方法,HttpObject就是一个http请求的封装对象, 类似于java中在request和resone之前的对象
        //System.err.println("类MyHttpControllerHandler中的方法channelRead0执行了");
        //所有的请求都会到达这里,相当于我们有一个拦截了所有地址的servlet
        //我们需要根据具体的请求地址来获取到要执行的controller和方法
        //  System.err.println(httpObject);
        if (httpObject instanceof HttpRequest) {
            //如果是http请求
            String uri = ((DefaultHttpRequest) httpObject).uri();//获取到正在请求的地址
            if ("/favicon.ico".equals(uri)) {
                return;
            }
            Map parametersMap = new HashMap<>();
            System.err.println(uri);
            String path = uri;//默认情况下,请求的路径是整个地址,如果包含?再重新裁剪

            if (uri.contains("?")) {//如果传递了参数 才去解析参数
                 path = uri.substring(0, uri.indexOf("?"));//请求的路径
                String queryString = uri.substring(uri.lastIndexOf("?") + 1);//传递的参数
                //上面的参数可能包含多个参数, 用&分割,我们需要先分割
                String[] split = queryString.split("&");//a=b  x=y
                for (String s : split) {
                    //每一个参数的键值对,用=连接起来的
                    String[] split1 = s.split("=");//每一个参数的键值对
                    //  System.err.println(Arrays.asList(split1));
                    parametersMap.put(split1[0], split1[1]);//保存所有的参数
                }
                System.err.println(parametersMap);
            }

            //根据请求的路径,找到执行的方法, 然后执行方法,把参数传递过去
            Map<String, Method> url2Method = RquestUtils.url2Method;//地址和方法的关系
            Map<String, Object> url2Controller = RquestUtils.url2Controller;//地址和类对象之间的关系,这个对象的目的是为了执行我们的方法

            Method method = url2Method.get(path);//找到当前路径对应的方法
            Object o = url2Controller.get(path);//方法所在的controller的类对象

            System.err.println(method);
            System.err.println(o);

            //我们在执行方法的时候发现,我们需要传递参数,并且不能传递错了,什么名字的参数的值必须传递到方法对应的名字上面
            //我们必须知道方法的每一个参数的名字分别是什么,以及在什么位置, 其实可以这样我们可以获取每个位置的参数的名字,然后找到对应的值,放到这里
            if (method != null) {
                Parameter[] parameters = method.getParameters();//找到所有的参数,这个顺序就是方法中参数的顺序
                Object[] values = new Object[parameters.length];//创建一个和方法参数一样长的数组,目的是,方法的第一个参数的值我们就放在这个数组的第一个位置,依次类推
                for (int i = 0; i < parameters.length; i++) {
                    Parameter parameter = parameters[i];//获取每一个位置的参数
                    String name = parameter.getName();//获取到这个参数的名字
                   // System.err.println("name=====>"+name);
                    //值在map中,所以根据当前的需要的参数名,从map中获取值
                    Object value = parametersMap.get(name);//传递的这个参数的值
                    values[i] = value;//给这个位置设置参数的值
                }
                //当上的循环结束了,那么我们的values数组就存放了这个方法需要的每个参数,并且是按照顺序的
                String result = (String) method.invoke(o, values);
                System.err.println(result);
                //我们是http请求,返回的应该是http的格式的数据,不然浏览器不认识这个数据
                ByteBuf byteBuf = Unpooled.copiedBuffer(result, StandardCharsets.UTF_8);
                DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf);
                response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html;charset=utf-8")
                        .set(HttpHeaderNames.CONTENT_LENGTH,byteBuf.readableBytes());
                channelHandlerContext.writeAndFlush(response);
            }

        }
    }
}
